/**
 * @addtogroup jtc_msg_808
 * jtc_msg_808
 * @{
 */
 /**
 * @file         jtc_msg_808.h
 * @brief        交通部消息808定义
 * @note    
 * @author       Akee
 * @date         2019-10-31
 * @version      1.0
 *
 * @par          修改日志
 * <table>
 * <tr><th>Date        <th>Version               <th>Author          <th>Description
 * <tr><td>2019-10-31  <td>1.0                   <td>Akee            <td>创建初始版本
 * @copyright    杭州鸿泉物联网技术股份有限公司
 */
#ifndef _JTC_MSG_808_H_
#define _JTC_MSG_808_H_

#include "ofc/ofc_types.h"
#include "ofc/ofc_object.h"
#include "jtc_msg_808_codec.h"

#ifdef __cplusplus
extern "C" {
#endif
 /// 交通部消息编解码方法赋值宏
#define ASSIGN_JT_MSG_808_CODEC_METHOD(name, method) \
    self->parent_.name = method;

/**
 * 交通部消息808Id枚举
 */
enum TJtMsg808IdMsgIdEnumTag
{
    /// 以下为2013版本
    kJtMsg808IdTrmGenResp           = 0x0001, ///< 终端通用应答
    kJtMsg808IdPtmGenResp           = 0x8001, ///< 平台通用应答
    kJtMsg808IdRequestPkgPart       = 0x8003, ///< 补传分包请求
    kJtMsg808IdTrmBeat              = 0x0002, ///< 终端心跳
    kJtMsg808IdTrmRegister          = 0x0100, ///< 终端注册
    kJtMsg808IdTrmRegisterResp      = 0x8100, ///< 终端注册应答
    kJtMsg808IdTrmLogout            = 0x0003, ///< 终端注销
    kJtMsg808IdTrmAuth              = 0x0102, ///< 终端鉴权
    kJtMsg808IdSetParams            = 0x8103, ///< 设置参数
    kJtMsg808IdGetParam             = 0x8104, ///< 查询终端参数
    kJtMsg808IdGetParamResp         = 0x0104, ///< 查询终端参数
    kJtMsg808IdTrmCtrl              = 0x8105, ///< 终端控制
    kJtMsg808IdGetParams            = 0x8106, ///< 查询指定终端参数
    kJtMsg808IdGetTrmAttr           = 0x8107, ///< 查询终端属性
    kJtMsg808IdGetTrmAttrResp       = 0x0107, ///< 查询终端属性应答
    kJtMsg808IdTrmUpdate            = 0x8108, ///< 下发终端升级包
    kJtMsg808IdTrmUpdateResult      = 0x0108, ///< 终端升级结果通知
    kJtMsg808IdAccountRegister      = 0x0110, ///< 使用前锁定(快速开户)消息
    kJtMsg808IdLocation             = 0x0200, ///< 位置信息汇报
    kJtMsg808IdGetLocation          = 0x8201, ///< 位置信息查询
    kJtMsg808IdGetLocationResp      = 0x0201, ///< 位置信息查询应答
    kJtMsg808IdLocationTrace        = 0x8202, ///< 临时位置跟踪控制
    kJtMsg808IdManualConfAlarm      = 0x8203, ///< 人工确认报警消息
    kJtMsg808IdTextMsg              = 0x8300, ///< 文本信息下发
    kJtMsg808IdEventSet             = 0x8301, ///< 事件设置
    kJtMsg808IdEventReport          = 0x0301, ///< 事件报告
    kJtMsg808IdQuestion             = 0x8302, ///< 提问下发
    kJtMsg808IdQuestionResp         = 0x0302, ///< 提问应答
    kJtMsg808IdMsgReqMenuSet        = 0x8303, ///< 信息点播菜单设置
    kJtMsg808IdMsgRequest           = 0x0303, ///< 信息点播/取消
    kJtMsg808IdMsgService           = 0x8304, ///< 信息服务
    kJtMsg808IdPhoneCallBack        = 0x8400, ///< 电话回拨
    kJtMsg808IdSetAddrBook          = 0x8401, ///< 设置电话本
    kJtMsg808IdVehicleCtrl          = 0x8500, ///< 车辆控制
    kJtMsg808IdVehicleCtrlResp      = 0x0500, ///< 车辆控制应答
    kJtMsg808IdSetCircleZone        = 0x8600, ///< 设置圆形区域
    kJtMsg808IdDelCircleZone        = 0x8601, ///< 删除圆形区域
    kJtMsg808IdSetRectZone          = 0x8602, ///< 设置矩形区域
    kJtMsg808IdDelRectZone          = 0x8603, ///< 删除矩形区域
    kJtMsg808IdSetPolygonZone       = 0x8604, ///< 设置多边形区域
    kJtMsg808IdDelPolygonZone       = 0x8605, ///< 删除多边形区域
    kJtMsg808IdSetLine              = 0x8606, ///< 设置路线
    kJtMsg808IdDelLine              = 0x8607, ///< 删除路线
    kJtMsg808IdGetVtdrData          = 0x8700, ///< 行驶记录数据采集命令
    kJtMsg808IdGetVtdrDataResp      = 0x0700, ///< 行驶记录数据上传
    kJtMsg808IdGetDriver            = 0x8702, ///< 上报驾驶员身份信息请求
    kJtMsg808IdSetVtdrParam         = 0x8701, ///< 行驶记录参数下传命令
    kJtMsg808IdGetEBill             = 0x0701, ///< 电子运单上报
    kJtMsg808IdGetDriverResp        = 0x0702, ///< 驾驶员身份信息采集上报
    kJtMsg808IdLocationBatch        = 0x0704, ///< 定位数据批量上传
    kJtMsg808IdCanData              = 0x0705, ///< Can总线数据上传
    kJtMsg808IdMediaEvent           = 0x0800, ///< 多媒体事件信息上传
    kJtMsg808IdMediaData            = 0x0801, ///< 多媒体数据上传
    kJtMsg808IdMediaDataResp        = 0x8800, ///< 多媒体数据上传应答
    kJtMsg808IdCameraSnap           = 0x8801, ///< 摄像头立即拍摄命令
    kJtMsg808IdMediaQuery           = 0x8802, ///< 存储多媒体数据检索
    kJtMsg808IdMediaQueryResp       = 0x0802, ///< 存储多媒体数据检索应答
    kJtMsg808IdMediaStoreData       = 0x8803, ///< 存储多媒体数据上传命令
    kJtMsg808IdStartRecord          = 0x8804, ///< 录音开始命令
    kJtMsg808IdCameraSnapResp       = 0x0805, ///< 摄像头立即拍摄命令应答
    kJtMsg808IdMediaQueryOne        = 0x8805, ///< 单条多媒体数据检索上传
    kJtMsg808IdDownloadByPass       = 0x8900, ///< 数据下行透传
    kJtMsg808IdUploadByPass         = 0x0900, ///< 数据上行透传
    kJtMsg808IdCompressData         = 0x0901, ///< 数据压缩上报
    kJtMsg808IdPtmRsaPubKey         = 0x8A00, ///< 平台RSA公钥
    kJtMsg808IdTrmRsaPubKey         = 0x0A00, ///< 终端RSA公钥

    /// 以下为2019版本新增或者修改
    kJtMsg808IdQueryServerTime      = 0x0004, ///< 查询服务器时间请求
    kJtMsg808IdQueryServerTimeResp  = 0x8004, ///< 查询服务器时间应答
    kJtMsg808IdV19TrmRegister       = 0x0100, ///< 终端注册
    kJtMsg808IdV19TrmAuth           = 0x0102, ///< 终端鉴权
    kJtMsg808IdV19GetTrmAttrResp    = 0x0107, ///< 查询终端属性应答
    kJtMsg808IdLinkDetection        = 0x8204, ///< 链路检测
    kJtMsg808IdV19TextMsg           = 0x8300, ///< 文本信息下发
    kJtMsg808IdV19VehicleCtrl       = 0x8500, ///< 车辆控制
    kJtMsg808IdV19SetCircleZone     = 0x8600, ///< 设置圆形区域
    kJtMsg808IdV19SetRectZone       = 0x8602, ///< 设置矩形区域
    kJtMsg808IdV19SetPolygonZone    = 0x8604, ///< 设置多边形区域
    kJtMsg808IdV19SetLine           = 0x8606, ///< 设置路线
    kJtMsg808IdQueryZoneData        = 0x8608, ///< 查询区域或线路数据
    kJtMsg808IdQueryZoneDataResp    = 0x0608, ///< 查询区域或线路数据应答
    kJtMsg808IdV19GetDriverResp     = 0x0702, ///< 驾驶员身份信息采集上报
    kJtMsg808IdAgnssDownloadRequest = 0x0FD4,   ///< GNSS 星历下载请求
    kJtMsg808IdAgnssDownloadRespond = 0x8FD4,   ///< GNSS 星历下载请求应答
};
typedef enum TJtMsg808IdMsgIdEnumTag TJtMsg808IdMsgIdEnum;

typedef struct TJtMsg808Tag TJtMsg808;
struct TJtMsg808MgrTag;
struct IJtMsg808SessionTag;
/**
 * 构造事件
 * @param sender: 对象指针
 * @return True: 成功; False: 失败
 */
typedef Bool (*TJtMsg808DoCreateEvent)(TJtMsg808 *self);

/**
 * 消息处理事件
 * @param sender: 发起者,这里指TJtMsg808
 * @param receiver: 接收者
 * @return
 */
typedef void(*TJtMsg808DoMsgProcEvent)(TJtMsg808 *sender, void *receiver, struct IJtMsg808SessionTag *session);

/**
* 消息处理事件
*/
typedef struct TJtMsg808OnMsgProcEventTag TJtMsg808OnMsgProcEvent;
struct TJtMsg808OnMsgProcEventTag
{
    void *object;
    TJtMsg808DoMsgProcEvent Method;
};

/**
 * 编码事件
 * @param sender: 对象指针
 * @param encode_buf: 编码后存放的数据缓冲
 * @param encode_buf_size: 编码存放的数据大小
 * @return >=0: 编码成功,编码后的字节数; <0: 编码失败
 */
typedef Int32 (*TJtMsg808DoEncodeEvent)(TJtMsg808 *self, struct TJtMsg808MgrTag *msg_mgr, Byte *encode_buf, Int32 encode_buf_size);

/**
 * 解码事件
 * @param sender: 对象指针
 * @param decode_buf: 需要解码的数据缓冲,已经反转义后的数据，不包含头尾0x7E,包含消息和校验码
 * @param decode_buf_size: 需要解码的数据大小
 * @return True: 解码成功; False: 解码失败
 */
typedef Bool (*TJtMsg808DoDecodeEvent)(TJtMsg808 *self, struct TJtMsg808MgrTag *msg_mgr, Byte *decode_buf, Int32 decode_buf_size);


/**
 * 存储消息类型
 */
#pragma pack(push, 1)
typedef struct TJtMsg808StoreTag TJtMsg808Store;
struct TJtMsg808StoreTag
{
    Word msg_id;                ///< 消息id
    Word msg_count;             ///< 消息总包数,从1开始
    Word msg_index;             ///< 消息包序,从0开始
    Byte ver;                   ///< 消息版本,参考TJtMsg808VerEnum,默认采用2013版本
    Byte encrypt_type_;         ///< 加密方式,参考TJtMsg808EncryptTypeEnum
    Word msg_len;               ///< 消息长度

    // here is data...
};
#pragma pack(pop)

/**
 * 交通部消息808基类
 */
struct TJtMsg808Tag
{
PROTECTED
    TOfObject parent_;          ///< 基类

PUBLIC
    TJtMsg808DoEncodeEvent DoEncode_;   ///< 编码事件
    TJtMsg808DoDecodeEvent DoDecode_;   ///< 解码事件

PROTECTED
    TOfVirtualMethod Destroy_;  ///< 析构事件

PRIVATE
    Word msg_id_;                ///< 消息id
    Word seq_id_;                ///< 消息流水号id
    Word msg_count_;             ///< 消息总包数,从1开始
    Word msg_index_;             ///< 消息包序,从0开始
    Byte encrypt_type_;          ///< 加密方式,参考TJtMsg808EncryptTypeEnum
    Byte ver_;                   ///< 消息版本,参考TJtMsg808VerEnum,默认采用2013版本
    Word msg_encode_size_;       ///< 消息编码后的长度,未编码时为0
    Bool ver_valid_;             ///< 版本是否有效
    Bool seq_id_vaild_;
    DWord last_tick_;            ///< 最后的消息时间，单位:ms
    DWord try_index_;            ///< 尝试索引次数
};

/**
 * 交通部消息808基类构造函数
 * @param self: 对象指针
 * @return 
 */
void TJtMsg808Create(TJtMsg808 *self);

/**
 * 从msg_head中获取消息头信息
 * @param self: 对象指针
 * @param msg_head: 消息头
 * @return 肯定是True,为了链式编程
 */
Bool TJtMsg808GetMsgHead(TJtMsg808 *self, struct TJtMsg808HeadTag *msg_head);

/**
 * 编码函数
 * @param self: 对象指针
 * @param msg_mgr: 消息管理器
 * @param buf: 编码后的数据内存存放地址
 * @param buf_size: 编码的数据存放大小
 * @return >0: 编码成功,编码后的大小; <=0: 编码失败
 */
Int32 TJtMsg808Encode(TJtMsg808 *self, struct TJtMsg808MgrTag *msg_mgr, Byte *buf, Int32 buf_size);

/**
 * 编码函数，针对子消息类型进行编码
 * @param self: 对象指针
 * @param msg_mgr: 消息管理器
 * @param buf: 针对子消息的buf内容进行编码，例如8105的具体pdu
 * @param buf_size: 针对子消息的buf内容进行编码，例如8105的具体pdu大小
 * @return >0: 编码成功,编码后的大小; <=0: 编码失败
 */
Int32 TJtMsg808SubEncode(TJtMsg808 *self, struct TJtMsg808MgrTag *msg_mgr, Byte *buf, Int32 buf_size);

/**
* 解码函数
* @param self: 对象指针
* @param msg_mgr: 消息管理器
* @param buf: 需要解码的数据缓冲,已经反转义后的数据，不包含头尾0x7E,包含消息和校验码
* @param buf_size: 需要解码的数据大小
* @return True: 解码成功; False: 解码失败
*/
Bool TJtMsg808Decode(TJtMsg808 *self, struct TJtMsg808MgrTag *msg_mgr, Byte *buf, Int32 buf_size);

/**
* 解码函数,针对子消息类型进行解码
* @param self: 对象指针
* @param msg_mgr: 消息管理器
* @param buf: 针对子消息的buf内容进行解析，例如8105的具体pdu
* @param buf_size: 针对子消息的buf内容进行解析，例如8105的具体pdu大小
* @return True: 解码成功; False: 解码失败
*/
Bool TJtMsg808SubDecode(TJtMsg808 *self, struct TJtMsg808MgrTag *msg_mgr, Byte *buf, Int32 buf_size);

/**
 * 获取消息编码后的长度
 * @param self: 对象指针
 * @return 编码后的大小
 * @note 需要调用TJtMsg808Encode后才会得到此尺寸，否则为0
 */
Word TJtMsg808MsgEncodeSize(TJtMsg808 *self);

/**
 * 获取消息Id
 * @param self: 对象指针
 * @return 消息Id
 */
Word TJtMsg808MsgId(TJtMsg808 *self);

/**
 * 设置消息Id
 * @param self: 对象指针
 * @param value: 消息Id
 * @return 
 */
void TJtMsg808SetMsgId(TJtMsg808 *self, Word value);

/**
 * 获取消息流水号
 * @param self: 对象指针
 * @return 消息流水号
 */
Word TJtMsg808SeqId(TJtMsg808 *self);

/**
 * 设置消息流水号
 * @param self: 对象指针
 * @param value: 消息流水号
 * @return 
 * @note 设置过流水号后，不再引用管理器中的流水号
 */
void TJtMsg808SetSeqId(TJtMsg808 *self, Word value);

/**
 * 获取消息总包数,从1开始
 * @param self: 对象指针
 * @return 消息总包数
 */
Word TJtMsg808MsgCount(TJtMsg808 *self);

/**
 * 设置消息总包数
 * @param self: 对象指针
 * @param value: 消息总包数
 * @return 
 */
void TJtMsg808SetMsgCount(TJtMsg808 *self, Word value);

/**
 * 获取消息当前包索引,从0开始
 * @param self: 对象指针
 * @return 消息当前包索引
 */
Word TJtMsg808MsgIndex(TJtMsg808 *self);

/**
 * 设置消息当前包索引
 * @param self: 对象指针
 * @param value: 消息当前包索引
 * @return 
 */
void TJtMsg808SetMsgIndex(TJtMsg808 *self, Word value);

/**
 * 获取消息加密方式
 * @param self: 对象指针
 * @return 加密方式
 */
Byte TJtMsg808EncryptType(TJtMsg808 *self);

/**
 * 设置消息加密方式
 * @param self: 对象指针
 * @param value: 加密方式
 * @return 
 */
void TJtMsg808SetEncryptType(TJtMsg808 *self, Byte value);

/**
 * 析构消息并释放内存
 * @param self: 析构并释放的对象指针
 * @return
 */
void TJtMsg808FreeMsg(TJtMsg808 *self);

/**
 * 设置消息的最后时间
 * @param self: 对象指针
 * @param tick: 最后时间，单位: ms
 * @return
 */
void TJtMsg808SetLastTick(TJtMsg808 *self, DWord tick);

/**
 * 消息是否已经超时
 * @param self: 对象指针
 * @param curr_tick: 当前时间，单位: ms
 * @param msg_mgr: 消息管理器
 * @return True: 超时; False: 没有超时
 */
Bool TJtMsg808IsTimeOut(TJtMsg808 *self, DWord curr_tick, struct TJtMsg808MgrTag *msg_mgr);

/**
 * 增加重试次数
 * @param self: 对象指针
 * @param curr_tick: 当前时间，单位: ms
 * @param msg_mgr: 消息管理器
 * @return True: 成功; False: 失败
 */
Bool TJtMsg808IncRetryCount(TJtMsg808 *self, DWord curr_tick, struct TJtMsg808MgrTag *msg_mgr);

/**
 * 消息版本是否有效，若无效则使用消息管理器的版本，默认无效
 * @param self: 对象指针
 * @return True: 有效; False: 无效
 */
Bool TJtMsg808VerValid(TJtMsg808 *self);

/**
 * 设置消息版本是否有效，若无效则使用消息管理器的版本
 * @param self: 对象指针
 * @return 
 */
void TJtMsg808SetVerValid(TJtMsg808 *self, Bool valid);

/**
 * 获取消息版本号
 * @param self: 对象指针
 * @return 消息版本,参考TJtMsg808VerEnum
 */
Byte TJtMsg808Ver(TJtMsg808 *self);

/**
 * 设置消息版本号，设置后，直接采用消息本身的版本号
 * @param self: 对象指针
 * @param ver: 消息版本,参考TJtMsg808VerEnum
 * @return 
 */
void TJtMsg808SetVer(TJtMsg808 *self, Byte ver);

#ifdef __cplusplus
} // extern "C" {
#endif
#endif
/**
 * @} 
 */



